package com.googlecode.gwtbb.server.service;

import com.googlecode.gwtbb.client.shared.entity.forum.Forum;
import com.googlecode.gwtbb.client.shared.entity.forum.ForumBase;
import com.googlecode.gwtbb.client.shared.entity.forum.ForumSnap;
import com.googlecode.gwtbb.client.shared.entity.forum.Post;
import com.googlecode.gwtbb.client.shared.entity.user.User;
import com.googlecode.gwtbb.client.shared.remote.forum.CreateForumBean;
import com.googlecode.gwtbb.client.shared.remote.forum.CreateForumResponse;
import com.googlecode.gwtbb.client.shared.remote.forum.ForumPosts;
import com.googlecode.gwtbb.client.shared.validation.Failure;
import com.googlecode.gwtbb.client.shared.validation.FieldId;
import com.googlecode.gwtbb.client.shared.validation.GwtbbValidator;
import com.googlecode.gwtbb.server.dao.forum.ForumDao;
import com.googlecode.gwtbb.server.dao.forum.ForumSnapDao;
import com.googlecode.gwtbb.server.dao.forum.PostDao;
import com.googlecode.gwtbb.server.intermediate.Meta;
import com.googlecode.gwtbb.server.intermediate.ProcessNames;
import com.googlecode.gwtbb.server.intermediate.forum.ForumAssembler;
import com.googlecode.gwtbb.server.intermediate.forum.PostAssembler;
import com.googlecode.gwtbb.server.intermediate.user.PrivilegeChecker;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Date;

/**
 * @author Abraham Grief
 * @version $Id$
 * @noinspection unchecked
 * @since May 4, 2008
 */
public class ForumService implements com.googlecode.gwtbb.client.only.remote.forum.ForumService {
	private ForumAssembler forumAssembler;
	private ForumDao forumDao;
	private ForumSnapDao forumSnapDao;
	private PostAssembler postAssembler;
	private PostDao postDao;
	private PrivilegeChecker privilegeChecker;

	public ForumAssembler getForumAssembler() {
		return forumAssembler;
	}

	public void setForumAssembler(ForumAssembler forumAssembler) {
		this.forumAssembler = forumAssembler;
	}

	public ForumDao getForumDao() {
		return forumDao;
	}

	public void setForumDao(ForumDao forumDao) {
		this.forumDao = forumDao;
	}

	public ForumSnapDao getForumSnapDao() {
		return forumSnapDao;
	}

	public void setForumSnapDao(ForumSnapDao forumSnapDao) {
		this.forumSnapDao = forumSnapDao;
	}

	public PostAssembler getPostAssembler() {
		return postAssembler;
	}

	public void setPostAssembler(PostAssembler postAssembler) {
		this.postAssembler = postAssembler;
	}

	public PostDao getPostDao() {
		return postDao;
	}

	public void setPostDao(PostDao postDao) {
		this.postDao = postDao;
	}

	public PrivilegeChecker getPrivilegeChecker() {
		return privilegeChecker;
	}

	public void setPrivilegeChecker(PrivilegeChecker privilegeChecker) {
		this.privilegeChecker = privilegeChecker;
	}

	@Transactional
	public CreateForumResponse create(Long userId, String sessionId, CreateForumBean createForumBean) {
		if (userId == null || sessionId == null || createForumBean == null)
			return null;

		Forum forum = null;
		CreateForumResponse retVal = new CreateForumResponse();
		Map<FieldId, Failure> failures = createForumBean.validate(GwtbbValidator.newMap(), 0);
		User actor = privilegeChecker.checkPrivilege(failures, userId, sessionId, User.PrivilegeLevel.ADMIN);
		if (failures.isEmpty()) {
			Date snapDate = new Date();
			forum = new Forum(null, createForumBean.getName(), createForumBean.getDescription(), createForumBean.isListed(), false, snapDate);
			forumDao.create(forum);
			forumSnapDao.create(newForumSnap(forum, actor, ProcessNames.CREATE_FORUM));
			failures = null;
		}
		retVal.setFailures(failures);
		retVal.setForum(forum);
		return retVal;
	}

	public ForumPosts getForumThreadPosts(Long threadId) {
		ForumPosts retVal = new ForumPosts();
		List<Post> posts = postAssembler.assemble(postDao.selectPostsByThreadId(threadId));
		if (posts != null && !posts.isEmpty()) {
			retVal.setPosts(posts);
			Post post = posts.get(0);
			retVal.setForum(forumDao.select(post.getForumId()));
		}
		return retVal;
	}

	@Transactional
	public ForumPosts getForumThreads(Long forumId) {
		ForumPosts retVal = new ForumPosts();
		retVal.setForum(forumDao.select(forumId));
		retVal.setPosts(postAssembler.assemble(postDao.selectThreadsByForumId(forumId)));
		return retVal;
	}

	public List<Forum> getForumsWithInfo() {
		return forumAssembler.assemble(forumDao.selectListed());
	}

	private static ForumSnap newForumSnap(Forum forum, User actor, String process) {
		return Meta.instantiateSnapshot(ForumSnap.class, forum, ForumBase.PROPERTIES, actor.getId(), process);
	}
}
